import { Box3, BufferGeometry, Mesh, Object3D, Texture, Vector3 } from "three";

export default class MeshUtil {
  public static createAlphaTexture(width = 256, height = 256) {
    // 创建一个全透明的图像
    // var width = 256;
    // var height = 256;
    var canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;
    var context = canvas.getContext('2d');
    context.fillStyle = 'rgba(0, 0, 0, 0)'; // 设置为全透明
    context.fillRect(0, 0, width, height);
    // 创建一个纹理
    var texture = new Texture(canvas);
    texture.needsUpdate = true; // 确保纹理被更新
    texture['alphaTexture'] = true;
    return texture;
  }

  public static dispose(node) {
    if (!node) {
      return;
    }
    this.disposeNode(node);

    if(node.children){
        let childrenArray = []; //node.children;
        node.children.forEach(element => {
          childrenArray.push(element)
        });
    
        for (let i = 0; i < childrenArray.length; i++) {
          let child = childrenArray[i];
          this.disposeHierarchy(child);
        }
    }
   

    //释放gpu缓存资源
    // App.getInstance().three.renderer.renderLists.dispose();
  }

  static disposeNode(node) {
    if (node instanceof Mesh) {
      if (node.geometry) {
        node.geometry.dispose();
      }

      if (node.material) {
        if (node.material.length > 1) {
          let self = this;
          node.material.forEach(element => {
            self.disposeMaterial(element);
          });
        } else {
          this.disposeMaterial(node);
          node.material.dispose();   // disposes any programs associated with the material
        }
      }

    }

    if (node.parent) {
      node.parent.remove(node);
    }
  }

  private static disposeMaterial(node) {
    if (node.material.map) node.material.map.dispose();
    if (node.material.lightMap) node.material.lightMap.dispose();
    if (node.material.bumpMap) node.material.bumpMap.dispose();
    if (node.material.normalMap) node.material.normalMap.dispose();
    if (node.material.specularMap) node.material.specularMap.dispose();
    if (node.material.envMap) node.material.envMap.dispose();
    if (node.material.alphaMap) node.material.alphaMap.dispose();
    if (node.material.aoMap) node.material.aoMap.dispose();
    if (node.material.displacementMap) node.material.displacementMap.dispose();
    if (node.material.emissiveMap) node.material.emissiveMap.dispose();
    if (node.material.gradientMap) node.material.gradientMap.dispose();
    if (node.material.metalnessMap) node.material.metalnessMap.dispose();
    if (node.material.roughnessMap) node.material.roughnessMap.dispose();

    //处理shadermaterial
    if (node.material['uniforms']) {
      for (const value of Object.values(node.material['uniforms'])) {
        if (value) {
          const uniformValue = value['value'];
          if (uniformValue instanceof Texture) {
            uniformValue.dispose();
          }
          if (Array.isArray(uniformValue)) {
            uniformValue.length = 0;
          }
        }
      }
    }
  }

  /**
   * 释放节点资源。包括geometry和matrial
   * @param node 
   * @param callback 
   */
  static disposeHierarchy(node) {
    if(!node){
      return;
    }
    this.disposeNode(node);

    // for (var i = node.children.length - 1; i >= 0; i--) {
    //   var child = node.children[i];
    //   this.disposeHierarchy(child, callback);
    //   callback(child);
    // }

    if(node.children){
      let childrenArray = [];
      node.children.forEach(element => {
        childrenArray.push(element)
      });

      childrenArray.forEach(child => {
        this.disposeHierarchy(child);
        this.disposeNode(child);
      });
    }
  }

  public static getMeshBoundingBox(mesh) {
    if (!mesh.geometry.boundingBox) {
      mesh.geometry.computeBoundingBox();
    }
    var boundingBox: Box3 = (mesh.geometry as BufferGeometry).boundingBox.clone();
    var center = new Vector3();
    boundingBox.getCenter(center);
    var size = new Vector3();
    boundingBox.getSize(size);
    size.multiplyScalar(1.5);
    var expandedBox = new Box3();
    expandedBox.setFromCenterAndSize(center, size);
    boundingBox = expandedBox;

    var matrixWorld = mesh.matrixWorld;
    boundingBox.applyMatrix4(matrixWorld);
    return boundingBox;
  }

  public static computeBox(mesh: Object3D){
        let groupBoundingBox = new Box3();
        // let self = this;
        // 遍历group中的每个子对象，将它们的世界边界合并到groupBoundingBox中
        mesh.traverse(function (child) {
            if (child instanceof Mesh) {
                var childBoundingBox = new Box3().setFromObject(child);
                groupBoundingBox.union(childBoundingBox); // 合并边界框
            }
        });
        return groupBoundingBox;
  }

}
